Windows EC2インスタンスのDNS設定をPowerShellから行う
しばたです。
本記事はWindows Server 2012以降が対象で、EC2インスタンスに限らずどの環境のWindows Serverでも適用可能な内容となります。
今回EC2インスタンスで検証したのでこの様なタイトルにしてあります。
DNS設定を行うPowerShellコマンドレット
Windows Server 2012からネットワーク接続のDNSサーバー設定を行うために以下のコマンドレットが追加されています。
他にもDnsClientモジュールとして様々なコマンドレットが提供されています。
WindowsのNIC名称(InterfaceAlias)
ここでSet-DnsClientServerAddressコマンドレットを使うには対象NICの指定が必要で、この指定はInterfaceIndex
パラメーターで番号指定するのが原則なのですが、この番号はマシン毎で変わるため現実的にはNIC名称であるInterfaceAlias
パラメーターを指定することが多いかと思います。
# NICのインデックスがあらかじめわかっている場合
Set-DnsClientServerAddress -InterfaceIndex 1 -ServerAddresses @("192.168.1.xxx", "192.168.1.yyy")
# NIC名称(InterfaceAlias)を指定する場合
Set-DnsClientServerAddress -InterfaceAlias "イーサネット" -ServerAddresses @("192.168.1.xxx", "192.168.1.yyy")
ただ、WindowsにおいてNIC名称はOSバージョンや言語によって変わってしまうため一意に決めるのが非常に難しく、Windowsの非常にイケていない部分の一つでもあります。
(英語版Windows)
(日本語版Windows)
とはいえ、このコマンドレットが使えるWindows Server 2012以降のEC2においてはEthernet
およびイーサーネット
で始まるものと考えて差し支えないでしょう。
(複数ENIをアタッチし複数NICとなる場合は連番が付きます)
また、DNS設定可能なNICの一覧はGet-DnsClientコマンドレットで取得できます。
Get-DnsClient
Windows EC2インスタンスのDNS設定をPowerShellから行う
ここまでを踏まえてWindows EC2インスタンスのDNS設定を行うスクリプトを以下に記載します。
#
# このコマンドは Windows Server 2012以降で実行可能
#
# DNSサーバーの一覧を配列定義
$dnsServers = @("192.168.1.xxx", "192.168.1.yyy")
# NICの名称は言語ごとで異なるので注意
$nicAlias = switch ((Get-Culture).LCID) {
1041 {"イーサネット*"; break}
Default {"Ethernet*" ; break}
}
# DNS Clientオブジェクト取得
$client = Get-DnsClient -InterfaceAlias $nicAlias
# 変更前設定確認
$client | Get-DnsClientServerAddress -AddressFamily IPv4
# 設定変更
$client | Set-DnsClientServerAddress -ServerAddresses $dnsServers
$client | Get-DnsClientServerAddress -AddressFamily IPv4
そんなに難しいことはしてませんが、OSの言語設定を見てEthernet
およびイーサーネット
で始まるNIC情報を取得、その情報をもとにSet-DnsClientServerAddressでDNSサーバー設定を実施しています。
最初の例ではInterfaceAlias
パラメーターを直接指定していましたが、Get-DnsClientで取得されるCIMオブジェクト[1]をパイプラインで引き渡すことも可能なためこのスクリプトではそうしています。
NICのプロパティ画面から見てもきちんと更新されています。
また、DNS設定を元に戻したい場合はSet-DnsClientServerAddressに-ResetServerAddresses
パラメーターを指定します。
# 元に戻したい場合
$client | Set-DnsClientServerAddress -ResetServerAddresses
$client | Get-DnsClientServerAddress -AddressFamily IPv4
これで元に戻りました。
【2019.10.05 追記】もっとEC2に特化した処理を考えてみた
最初にブログを公開した直後に「これインスタンスメタデータを使えば厳密にNIC特定できないかなぁ?」と思い至り調べてみました。
インスタンスメタデータにはPrivateなIPv4アドレスを取得するlocal-ipv4
データがあり、
インスタンスのプライベート IPv4 アドレス。複数のネットワークインターフェイスが存在する場合、これは eth0 デバイス (デバイス番号が 0 のデバイス) を示します。
と記載されています。
これを使えば複数NICある様な環境でも特定のNICだけ対象とすることができそうです。
インスタンスメタデータはInvoke-RestMethod
で以下の様にして取得することができますので、
Invoke-RestMethod http://169.254.169.254/latest/meta-data/local-ipv4
最終的に次の様な感じで特定NIC(eth0)のDNS設定を更新することができます。
# DNSサーバーの一覧を配列定義
$dnsServers = @("192.168.1.xxx", "192.168.1.yyy")
# インスタンスメタデータの local-ipv4 合致するIP情報からDNS Clientオブジェクトを取得
$client = Get-NetIPAddress |
Where-Object { $_.IPAddress -eq (Invoke-RestMethod http://169.254.169.254/latest/meta-data/local-ipv4) } |
Get-DnsClient
# 変更前設定確認
$client | Get-DnsClientServerAddress -AddressFamily IPv4
# 設定変更
$client | Set-DnsClientServerAddress -ServerAddresses $dnsServers
$client | Get-DnsClientServerAddress -AddressFamily IPv4
きちんと複数NICのうち特定のもの(イーサネット
)のみ更新できています。
【2019.10.05 追記】NICが一つしかない場合
また、NICが一つしかないことがはっきりしているのであればGet-NetAdapterコマンドレットが単一の結果を返すので、
# NIC情報からDNS Clientオブジェクト取得
$client = Get-NetAdapter | Get-DnsClient
# 変更前設定確認
$client | Get-DnsClientServerAddress -AddressFamily IPv4
# 設定変更
$client | Set-DnsClientServerAddress -ServerAddresses $dnsServers
$client | Get-DnsClientServerAddress -AddressFamily IPv4
の様に記述することも可能です。
こちらの方がNIC名称の判定が無くより汎用的な処理になりますね。
最後に
以上となります。
このスクリプトをユーザーデータに仕込んだりSSM Run Commandから実行することで設定の自動化ができますので機会があればぜひお試しください。
Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_DNSClient ↩︎